#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include <stdarg.h>
#include "cmd.h"

/** initial length of message buffer (B) */
#define CCMD_MSG_LEN_START 128

cmd_log_printer g_log_cb = NULL;


static int ccmd_vsprintf(char **str, int *str_len, int offset, const char *format, va_list ap)
{
    va_list ap2;
    int req_len;

    if (!*str_len)
    {
        *str_len = CCMD_MSG_LEN_START;
        *str = malloc(*str_len);
        if (!*str) 
        {
            req_len = -1;
            goto cleanup;
        }
    }

    va_copy(ap2, ap);

    /* learn how much bytes are needed */
    req_len = vsnprintf(*str + offset, *str_len - offset, format, ap);
    if (req_len == -1) 
    {
        goto cleanup;
    }
    else if (req_len >= *str_len - offset) 
    {
        /* the length is not enough */
        *str_len = req_len + offset + 1;
        *str = realloc(*str, *str_len);
        if (!*str) 
        {
            req_len = -1;
            goto cleanup;
        }

        /* now print the full message */
        req_len = vsnprintf(*str + offset, *str_len - offset, format, ap2);
        if (req_len == -1) 
        {
            goto cleanup;
        }
    }

cleanup:
    if (req_len == -1) 
    {
        free(*str);
        *str = NULL;
        fprintf(stderr, "ccmd_vsprintf error!");
    }

    va_end(ap2);
    return req_len;
}


void ccmd_log(uint32_t ll, const char *format, ...)
{
    if (NULL == g_log_cb)
    {
        return;
    }

    va_list ap;
    char *msg=NULL;
    int msg_len = 0;

    va_start(ap, format);
    int ret = ccmd_vsprintf(&msg, &msg_len, 0, format, ap);
    va_end(ap);

    if (ret < 0)
    {
        return;
    }

    g_log_cb(ll, msg);
    free(msg);
}


void set_cmd_log_printer(cmd_log_printer cb)
{
    g_log_cb = cb;
}


